{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "de36289b31078a0a",
   "metadata": {},
   "source": [
    "\n",
    "# 语法基础\n",
    "\n",
    "## 代码文件编码\n",
    "默认情况下，Python 3 源码文件以 UTF-8 编码，所有字符串都是 unicode 字符串。 当然你也可以为源码文件指定不同的编码：\n",
    "- *# -*- coding: utf-8 -*-*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10983b1d3ceaa08",
   "metadata": {},
   "source": [
    "## python保留字\n",
    "保留字即关键字，我们不能把它们用作任何标识符名称。Python 的标准库提供了一个 keyword 模块，可以输出当前版本的所有关键字："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54f28078b0e84deb",
   "metadata": {},
   "outputs": [],
   "source": [
    "import keyword\n",
    "\n",
    "keyword.kwlist"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7256852dddbaf8d1",
   "metadata": {},
   "source": [
    "## 注释\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e07b7f105c491aff",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 第一个注释\n",
    "# 第二个注释\n",
    "\n",
    "'''\n",
    "第三注释\n",
    "第四注释\n",
    "'''\n",
    "\n",
    "\"\"\"\n",
    "第五注释\n",
    "第六注释\n",
    "\"\"\"\n",
    "print(\"Hello, Python!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "645eeb3e64459179",
   "metadata": {},
   "source": [
    "## 多行语句"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "388db0fee9d34376",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Python 通常是一行写完一条语句，但如果语句很长，我们可以使用反斜杠 \\ 来实现多行语句，例如：\n",
    "item_one = 1\n",
    "item_two = 2\n",
    "item_three = 3\n",
    "\n",
    "total = item_one + \\\n",
    "        item_two + \\\n",
    "        item_three\n",
    "print(total)\n",
    "\n",
    "#在 [], {}, 或 () 中的多行语句，不需要使用反斜杠 \\，例如：\n",
    "total = ['item_one', 'item_two', 'item_three',\n",
    "         'item_four', 'item_five']\n",
    "print(total)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a86b5efcd8d10fc",
   "metadata": {},
   "source": [
    "## 等待用户输入\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a12010480d5ecbc8",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "input(\"\\n\\n按下 enter 键后退出。\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f64fcb5d23386e48",
   "metadata": {},
   "source": [
    "## print输出（格式化）\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29f65ab58de0c3b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = \"x\"\n",
    "y = 10\n",
    "# 换行输出\n",
    "print(x)\n",
    "\n",
    "print('---------')\n",
    "# 不换行输出\n",
    "print(x, end=\"\")\n",
    "print(x, end=\"\")\n",
    "print()\n",
    "\n",
    "#格式化输出\n",
    "\n",
    "##占位符，前面的数字，对于字符串表示长度，对于浮点数表示小数位数\n",
    "print(\"%7d\" % 100)\n",
    "print(\"%07d\" % 100)  # 带前导数\n",
    "print(\"%.7f你好\" % 100)\n",
    "print(\"%7s你好\" % \"hi\")\n",
    "print(\"a=%s,b=%d\" % (x, y))\n",
    "\n",
    "## f格式化输出\n",
    "name = \"hx\"\n",
    "age = 18\n",
    "print(f\"我是{name},年龄{age}\");\n",
    "text = \"你好\\n很好\";\n",
    "result = text.split(\"\\n\");\n",
    "for f in result:\n",
    "    print(f, end=\" \")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45f5c63407b15ae",
   "metadata": {},
   "source": [
    "\n",
    "## import 与 from...import\n",
    "- 在 python 用 import 或者 from...import 来导入相应的模块。\n",
    "- 将整个模块(somemodule)导入，格式为： import somemodule\n",
    "- 从某个模块中导入某个函数,格式为： from somemodule import somefunction\n",
    "- 从某个模块中导入多个函数,格式为： from somemodule import firstfunc, secondfunc, thirdfunc\n",
    "- 将某个模块中的全部函数导入，格式为： from somemodule import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48c2fcef000988de",
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入 sys 模块\n",
    "import sys\n",
    "\n",
    "print('================Python import mode==========================')\n",
    "print('命令行参数为:')\n",
    "for i in sys.argv:\n",
    "    print(i, end=\" \")\n",
    "print('\\n python 路径为', sys.path)\n",
    "\n",
    "#导入 sys 模块的 argv,path 成员\n",
    "from sys import argv, path  #  导入特定的成员\n",
    "\n",
    "print('================python from import===================================')\n",
    "print('path:', path)  # 因为已经导入path成员，所以此处引用时不需要加sys.path"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a4686573b692df7",
   "metadata": {},
   "source": [
    "## 变量类型\n",
    "  - 标准数据类型\n",
    "    - Numbers（数字）\n",
    "    - String（字符串）\n",
    "    - List（列表）\n",
    "    - Tuple（元组）\n",
    "    - Dictionary（字典）\n",
    "  - Python支持四种不同的数字类型：\n",
    "    - int（有符号整型）\n",
    "    - long（长整型，也可以代表八进制和十六进制）\n",
    "    - float（浮点型）\n",
    "    - complex（复数）\n",
    " ### 数字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "97203148cd0fe58e",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = b = c = 1\n",
    "a, b, c = 1, 2, \"john\"\n",
    "var1 = 1\n",
    "del var1\n",
    "# print(var1) ##被删除后，变量不可再使用\n",
    "\n",
    "aa, bb = 1.0, 2.0  # 错误写法aa=1.0,bb=2.0,与java有差别\n",
    "\n",
    "cc = complex(aa, bb)\n",
    "cc = 1.0 + 2.0j\n",
    "print(cc)\n",
    "print(type(cc))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b328a64e74a57c9",
   "metadata": {},
   "source": [
    "### 字符串\n",
    "<img src=\"string.png\" style=\"margin-left: 0px\" width=500px>\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f1b6614a46884363",
   "metadata": {},
   "outputs": [],
   "source": [
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "str = 'Hello World!'\n",
    "\n",
    "print(str)  # 输出完整字符串\n",
    "print(str[0])  # 输出字符串中的第一个字符\n",
    "print(str[2:5])  # 输出字符串中第三个至第六个之间的字符串\n",
    "print(str[2:])  # 输出从第三个字符开始的字符串\n",
    "print(str * 2)  # 输出字符串两次\n",
    "print(str + \"TEST\")  # 输出连接的字符串\n",
    "#字符串换行\n",
    "abc = '''你好，我好，大家好\n",
    "，但是我不好\n",
    "'''\n",
    "print(abc)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d67107a0d9fdcd63",
   "metadata": {},
   "source": [
    "### 列表\n",
    "<img src=\"list.png\" style=\"margin-left: 0px\" width=500px>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1bc9f81e98625de",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "list = ['runoob', 786, 2.23, 'john', 70.2]\n",
    "tinylist = [123, 'john']\n",
    "\n",
    "print(list)  # 输出完整列表\n",
    "print(list[0])  # 输出列表的第一个元素\n",
    "print(list[1:3])  # 输出第二个至第三个元素\n",
    "print(list[2:])  # 输出从第三个开始至列表末尾的所有元素\n",
    "print(tinylist * 2)  # 输出列表两次\n",
    "print(list + tinylist)  # 打印组合的列表"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a6694b5ab348b08",
   "metadata": {},
   "source": [
    "### 元组\n",
    "    元组不能二次赋值，相当于只读列表。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b4a42e865c74dbdc",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "tuple = ('runoob', 786, 2.23, 'john', 70.2)\n",
    "tinytuple = (123, 'john')\n",
    "\n",
    "print(tuple)  # 输出完整元组\n",
    "print(tuple[0])  # 输出元组的第一个元素\n",
    "print(tuple[1:3])  # 输出第二个至第四个（不包含）的元素\n",
    "print(tuple[2:])  # 输出从第三个开始至列表末尾的所有元素\n",
    "print(tinytuple * 2)  # 输出元组两次\n",
    "print(tuple + tinytuple)  # 打印组合的元组"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "408c3b56d10163a8",
   "metadata": {},
   "source": [
    "### 字典\n",
    "    字典(dictionary)是除列表以外python之中最灵活的内置数据结构类型。列表是有序的对象集合，字典是无序的对象集合。\n",
    "    两者之间的区别在于：字典当中的元素是通过键来存取的，而不是通过偏移存取。\n",
    "    字典用\"{ }\"标识。字典由索引(key)和它对应的值value组成。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1918a396b150864",
   "metadata": {},
   "outputs": [],
   "source": [
    "#!/usr/bin/python\n",
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "dict = {}\n",
    "dict['one'] = \"This is one\"\n",
    "dict[2] = \"This is two\"\n",
    "\n",
    "tinydict = {'name': 'runoob', 'code': 6734, 'dept': 'sales'}\n",
    "\n",
    "print(dict['one'])  # 输出键为'one' 的值\n",
    "print(dict[2])  # 输出键为 2 的值\n",
    "print(tinydict)  # 输出完整的字典\n",
    "print(tinydict.keys())  # 输出所有键\n",
    "print(tinydict.values())  # 输出所有值"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "601a18a27ce4d74a",
   "metadata": {},
   "source": [
    "## 函数\n",
    "### 函数调用\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e656a9ee0c2eb84",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "# 定义函数\n",
    "def echo(str):\n",
    "    \"\"\"输出字符串\"\"\"\n",
    "    return str\n",
    "\n",
    "\n",
    "# 调用函数\n",
    "a = echo(\"我要调用用户自定义函数!\")\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64c868c6f15b02e",
   "metadata": {},
   "source": [
    "### 不可变对象实例\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b93aee03a91cc7b",
   "metadata": {},
   "outputs": [],
   "source": [
    "#!/usr/bin/python\n",
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "def ChangeInt(a):\n",
    "    a = 10\n",
    "\n",
    "\n",
    "b = 2\n",
    "ChangeInt(b)\n",
    "print(b)  # 结果是 2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "620c0a7e2c8f0bb7",
   "metadata": {},
   "source": [
    "### 可变对象实例\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "156cf39ca5161132",
   "metadata": {},
   "outputs": [],
   "source": [
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "# 可写函数说明\n",
    "def changeme(mylist):\n",
    "    \"修改传入的列表\"\n",
    "    mylist.append([1, 2, 3, 4])\n",
    "    print(\"函数内取值: \", mylist)\n",
    "    return\n",
    "\n",
    "\n",
    "# 调用changeme函数\n",
    "mylist = [10, 20, 30]\n",
    "changeme(mylist)\n",
    "print(\"函数外取值: \", mylist)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fdebdbd5974e7a66",
   "metadata": {},
   "source": [
    "### 参数传递\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ef8ac60b6f0f420c",
   "metadata": {},
   "outputs": [],
   "source": [
    "#默认参数\n",
    "#!/usr/bin/python\n",
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "#可写函数说明\n",
    "def printinfo(name, age=35):\n",
    "    \"打印任何传入的字符串\"\n",
    "    print(\"Name: \", name)\n",
    "    print(\"Age \", age)\n",
    "    return\n",
    "\n",
    "\n",
    "#调用printinfo函数\n",
    "printinfo(age=50, name=\"miki\")\n",
    "printinfo(name=\"miki\")\n",
    "\n",
    "\"\"\"\"不定长参数，类似java的var ...\"\"\"\n",
    "\n",
    "\n",
    "# 可写函数说明\n",
    "def printinfo(arg1, *vartuple):\n",
    "    \"打印任何传入的参数\"\n",
    "    print(arg1)\n",
    "    for var in vartuple:\n",
    "        print(var)\n",
    "\n",
    "\n",
    "# 调用printinfo 函数\n",
    "printinfo(10)\n",
    "printinfo(70, 60, 50)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d793dfd29c35091e",
   "metadata": {},
   "source": [
    "### 匿名函数\n",
    "  python 使用 lambda 来创建匿名函数。\n",
    " - lambda只是一个表达式，函数体比def简单很多。\n",
    " - lambda的主体是一个表达式，而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。\n",
    " - lambda函数拥有自己的命名空间，且不能访问自有参数列表之外或全局命名空间里的参数。\n",
    " - 虽然lambda函数看起来只能写一行，却不等同于C或C++的内联函数，后者的目的是调用小函数时不占用栈内存从而增加运行效率。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af266a26bf35e094",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "# 可写函数说明\n",
    "sum = lambda arg1, arg2: arg1 + arg2\n",
    "# 调用sum函数\n",
    "print(\"相加后的值为 : \", sum(10, 20))\n",
    "print(\"相加后的值为 : \", sum(20, 20))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a82c224421a83775",
   "metadata": {},
   "source": [
    "\n",
    "### 装饰器（类似java的注解）\n",
    "    现在，假设我们要增强now()函数的功能，比如，在函数调用前后自动打印日志，但又不希望修改now()函数的定义，这种在代码运行期间动态增加功能的方式，称之为“装饰器”（Decorator）。\n",
    "    本质上，decorator就是一个返回函数的高阶函数。所以，我们要定义一个能打印日志的decorator，可以定义如下：\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61ad7687378d9046",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-31T09:40:53.261217Z",
     "start_time": "2025-03-31T09:40:53.258073Z"
    }
   },
   "outputs": [],
   "source": [
    "def log(func):\n",
    "    def wrapper(*args, **kw):\n",
    "        print('call %s():' % func.__name__)\n",
    "        return func(*args, **kw)\n",
    "\n",
    "    return wrapper\n",
    "\n",
    "\n",
    "#观察上面的log，因为它是一个decorator，所以接受一个函数作为参数，并返回一个函数。我们要借助Python的@语法，把decorator置于函数的定义处：\n",
    "\n",
    "\n",
    "@log\n",
    "def now():\n",
    "    print('2024-6-1')\n",
    "\n",
    "\n",
    "f = now()\n",
    "f\n",
    "#请设计一个decorator，它可作用于任何函数上，并打印该函数的执行时间：\n",
    "import time, functools\n",
    "\n",
    "def metric(fn):\n",
    "    print('%s executed in %s ms' % (fn.__name__, 10.24))\n",
    "    return fn\n",
    "\n",
    "# 测试\n",
    "@metric\n",
    "def fast(x, y):\n",
    "    time.sleep(0.0012)\n",
    "    return x + y;\n",
    "\n",
    "@metric\n",
    "def slow(x, y, z):\n",
    "    time.sleep(0.1234)\n",
    "    return x * y * z;\n",
    "\n",
    "f = fast(11, 22)\n",
    "s = slow(11, 22, 33)\n",
    "if f != 33:\n",
    "    print('测试失败!')\n",
    "elif s != 7986:\n",
    "    print('测试失败!')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71c9b9ea75d135d2",
   "metadata": {},
   "source": [
    "### 偏函数\n",
    "    偏函数就是固定一个函数的某些参数，返回一个偏函数。\n",
    "    functools.partial的作用就是，把一个函数的某些参数给固定住（也就是设置默认值），返回一个新的函数，调用这个新函数会更简单。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "979781c00379c82f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import functools\n",
    "\n",
    "int2 = functools.partial(int, base=2)\n",
    "\n",
    "print(\"1000000 =\", int2(\"1000000\"))\n",
    "\n",
    "# 相当于\n",
    "\n",
    "kw = {'base': 2}\n",
    "int('1000000', **kw)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad41c5368d05b92f",
   "metadata": {},
   "source": [
    "## 模块:类似java的包，类\n",
    "  搜索路径:当你导入一个模块，Python 解析器对模块位置的搜索顺序是：\n",
    "\n",
    " - 1、当前目录\n",
    " - 2、如果不在当前目录，Python 则搜索在 shell 变量 PYTHONPATH 下的每个目录。\n",
    " - 3、如果都找不到，Python会察看默认路径。UNIX下，默认路径一般为/usr/local/lib/python/。\n",
    "  模块搜索路径存储在 system 模块的 sys.path 变量中。变量里包含当前目录，PYTHONPATH和由安装过程决定的默认目录。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61514698cd1712cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "import support\n",
    "from python import support\n",
    "\n",
    "# 导入模块\n",
    "# import support\n",
    "\n",
    "# 现在可以调用模块里包含的函数了\n",
    "a = support.print_func(\"Runoob\")\n",
    "printinfo(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3f7d2ac4380a186c",
   "metadata": {},
   "source": [
    "### dir()函数\n",
    "    dir() 函数一个排好序的字符串列表，内容是一个模块里定义过的名字。\n",
    "    返回的列表容纳了在一个模块里定义的所有模块，变量和函数。如下一个简单的实例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e41201522c96dd1e",
   "metadata": {},
   "outputs": [],
   "source": [
    "#!/usr/bin/python\n",
    "# -*- coding: UTF-8 -*-\n",
    "\n",
    "# 导入内置math模块\n",
    "import support\n",
    "\n",
    "content = dir(support)\n",
    "\n",
    "print(content);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab2ae546a6e50758",
   "metadata": {},
   "source": [
    "### Python中的包\n",
    "    包是一个分层次的文件目录结构，它定义了一个由模块及子包，和子包下的子包等组成的 Python 的应用环境。\n",
    "    简单来说，包就是文件夹，但该文件夹下必须存在 __init__.py文件（python3不再请求，可初始一下东西，比如__all__、导入别的包等）, 该文件的内容可以为空。__init__.py 用于标识当前文件夹是一个包。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2490a56345439683",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入包\n",
    "from python.package1 import runoob1\n",
    "from python.package1 import runoob2\n",
    "\n",
    "runoob1.runoob1()\n",
    "runoob2.runoob2()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a1f1d66efc18047",
   "metadata": {},
   "source": [
    "### 作用域\n",
    "    与java的public，private，protect相似，只是python只要求变成习惯，不强制要求：具体参见package2中的文件引用package1中的内容"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97b850cc",
   "metadata": {},
   "source": [
    "## 异常处理\n",
    "与java类似：try...except...finally"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d919eb7",
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    print('try...')\n",
    "    r = 10 / int('1')\n",
    "    print('result:', r)\n",
    "except ValueError as e:\n",
    "    print('ValueError:', e)\n",
    "except ZeroDivisionError as e:\n",
    "    print('ZeroDivisionError:', e)\n",
    "else:\n",
    "    print('no error!')\n",
    "finally:\n",
    "    print('finally...')\n",
    "print('END')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa045fbb",
   "metadata": {},
   "source": [
    "### 调用栈"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "838faa95",
   "metadata": {},
   "outputs": [],
   "source": [
    "def foo(s):\n",
    "    return 10 / int(s)\n",
    "\n",
    "def bar(s):\n",
    "    return foo(s) * 2\n",
    "\n",
    "def main():\n",
    "    bar('0')\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03bb65d3",
   "metadata": {},
   "source": [
    "### 记录错误（使用logging）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa0a6be5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import logging\n",
    "\n",
    "def foo(s):\n",
    "    return 10 / int(s)\n",
    "\n",
    "def bar(s):\n",
    "    return foo(s) * 2\n",
    "\n",
    "def main():\n",
    "    try:\n",
    "        bar('0')\n",
    "    except Exception as e:\n",
    "        logging.exception(e)\n",
    "\n",
    "main()\n",
    "print('END')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60404307",
   "metadata": {},
   "source": [
    "### 抛出异常"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc754d04",
   "metadata": {},
   "outputs": [],
   "source": [
    "def foo(s):\n",
    "    n = int(s)\n",
    "    if n==0:\n",
    "        raise ValueError('invalid value: %s' % s)\n",
    "    return 10 / n\n",
    "\n",
    "def bar():\n",
    "    try:\n",
    "        foo('0')\n",
    "    except ValueError as e:\n",
    "        print('ValueError!')\n",
    "        raise\n",
    "\n",
    "bar()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1eea57ba042b4bf3",
   "metadata": {},
   "source": [
    "#  面向对象编程"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb9ed7985aa493",
   "metadata": {},
   "source": [
    "## 类和实例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53809ab9fdcf0828",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "## 无需像java那样定义字段名，是再构造方法定义的；\n",
    "class Student(object):\n",
    "\n",
    "    def __init__(self, name, score):\n",
    "        self.name = name\n",
    "        self.score = score\n",
    "\n",
    "    def print_score(self):\n",
    "        print(\"%s: %s\" % (self.name, self.score))\n",
    "\n",
    "    def get_grade(self):\n",
    "        if self.score >= 90:\n",
    "            return \"A\"\n",
    "        elif self.score >= 60:\n",
    "            return \"B\"\n",
    "        else:\n",
    "            return \"C\"\n",
    "\n",
    "\n",
    "bart = Student(\"Bart Simpson\", 59)\n",
    "lisa = Student(\"Lisa Simpson\", 87)\n",
    "\n",
    "print(\"bart.name =\", bart.name)\n",
    "print(\"bart.score =\", bart.score)\n",
    "bart.print_score()\n",
    "\n",
    "print(\"grade of Bart:\", bart.get_grade())\n",
    "print(\"grade of Lisa:\", lisa.get_grade())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2cbafe35fbbe3f71",
   "metadata": {},
   "source": [
    "## 访问限制\n",
    " - 如果要让内部属性不被外部访问，可以把属性的名称前加上两个下划线__，在Python中，实例的变量名如果以__开头，就变成了一个私有变量（private），只有内部可以访问，外部不能访问，所以，我们把Student类改一改：\n",
    "  - 需要注意的是，在Python中，变量名类似__xxx__的，也就是以双下划线开头，并且以双下划线结尾的，是特殊变量，特殊变量是可以直接访问的，不是private变量，所以，不能用__name__、__score__这样的变量名。\n",
    "  - 有些时候，你会看到以一个下划线开头的实例变量名，比如_name，这样的实例变量外部是可以访问的，但是，按照约定俗成的规定，当你看到这样的变量时，意思就是，“虽然我可以被访问，但是，请把我视为私有变量，不要随意访问”。\n",
    "  - 双下划线开头的实例变量是不是一定不能从外部访问呢？其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name，所以，仍然可以通过_Student__name来访问__name变量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bfcbb702d18602f",
   "metadata": {},
   "outputs": [],
   "source": [
    "#!/usr/bin/env python3\n",
    "# -*- coding: utf-8 -*-\n",
    "\n",
    "class Student(object):\n",
    "\n",
    "    def __init__(self, name, score):\n",
    "        self.__name = name\n",
    "        self.__score = score\n",
    "\n",
    "    def get_name(self):\n",
    "        return self.__name\n",
    "\n",
    "    def get_score(self):\n",
    "        return self.__score\n",
    "\n",
    "    def set_score(self, score):\n",
    "        if 0 <= score <= 100:\n",
    "            self.__score = score\n",
    "        else:\n",
    "            raise ValueError('bad score')\n",
    "\n",
    "    def get_grade(self):\n",
    "        if self.__score >= 90:\n",
    "            return 'A'\n",
    "        elif self.__score >= 60:\n",
    "            return 'B'\n",
    "        else:\n",
    "            return 'C'\n",
    "\n",
    "\n",
    "bart = Student('Bart Simpson', 59)\n",
    "print('bart.get_name() =', bart.get_name())\n",
    "bart.set_score(60)\n",
    "print('bart.get_score() =', bart.get_score())\n",
    "\n",
    "print('DO NOT use bart._Student__name:', bart._Student__name)\n",
    "# print(bart.__score) # 无法直接访问变量名了"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eaf669cfff50a053",
   "metadata": {},
   "source": [
    "## 继承与多态\n",
    " - 对于静态语言（例如Java）来说，如果需要传入Animal类型，则传入的对象必须是Animal类型或者它的子类，否则，将无法调用run()方法。\n",
    " - 对于Python这样的动态语言来说，则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了\n",
    " - 通过“鸭子类型”的方式，如果一个对象，有run()方法，就可以调用它。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be6010bd9193358f",
   "metadata": {},
   "source": [
    "## 获取对象信息\n",
    "- 基本类型都可以用type()判断：\n",
    " - 如果一个变量指向函数或者类，也可以用type()判断：\n",
    " - type()返回的对象类型就是type类型\n",
    " - 判断基本数据类型可以直接写int，str等，但如果要判断一个对象是否是函数怎么办？可以使用types模块中定义的常量：\n",
    "- 使用isinstance()\n",
    "- 使用dir()获取所有的属性和方法,类似java的反射,还可以动态加入新的属性哦。这体现了python的动态性\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f678f211ce4a457",
   "metadata": {},
   "source": [
    "## slots\n",
    "- 默认python的对象是可以动态添加属性和方法的，这在静态语言中很难实现。但是，如果定义了__slots__，那么，就只能从__slots__中定义的属性和方法访问。\n",
    "- 语法：__slots__ = ('name', 'age')\n",
    "- slots的使用，可以减少内存的使用，因为slots定义了允许添加的属性，所以，Python解释器可以针对该类进行优化，比如，__slots__定义的属性只能是定义的，所以，__slots__定义的属性在运行期就无法添加，这样就 speed up the attribute access，因为不需要进行属性的查找。\n",
    "- __slots__定义的属性只能是定义的，所以，__slots__定义的属性在运行期就无法添加，这样就 speed up the attribute access，因为不需要进行属性的查找。\n",
    "- 使用__slots__要注意，__slots__定义的属性仅对当前类实例起作用，对继承的子类是不起作用的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e96d8fed0bf3381",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    __slots__ = (\"name\", \"age\")  # 限制只有这两个属性\n",
    "\n",
    "\n",
    "class GraduateStudent(Student):\n",
    "    pass\n",
    "\n",
    "\n",
    "ss = Student()\n",
    "ss.name = \"Michael\"\n",
    "ss.age = 25\n",
    "# ERROR: AttributeError: 'Student' object has no attribute 'score'\n",
    "try:\n",
    "    ss.score = 99\n",
    "except AttributeError as e:\n",
    "    print(\"AttributeError:\", e)\n",
    "\n",
    "g = GraduateStudent()\n",
    "g.score = 99  #子类不受__slots__的限制，还是可以动态添加属性\n",
    "print(\"g.score =\", g.score)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69f70943d0edba94",
   "metadata": {},
   "source": [
    "## 多重继承\n",
    " - 区别于java的又一个重大属性\n",
    " - 多重继承的顺序是：先父类，再子类\n",
    " - 父类如果有相同的方法，子类会覆盖父类的方法\n",
    " - Python自带的很多库也使用了MixIn。举个例子，Python自带了TCPServer和UDPServer这两类网络服务，而要同时服务多个用户就必须使用多进程或多线程模型，这两种模型由ForkingMixIn和ThreadingMixIn提供。通过组合，我们就可以创造出合适的服务来。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a0dfcbaabefea920",
   "metadata": {},
   "outputs": [],
   "source": [
    "from socketserver import TCPServer, ForkingMixIn, UDPServer, ThreadingMixIn\n",
    "\n",
    "\n",
    "#比如，编写一个多进程模式的TCP服务，定义如下：\n",
    "class MyTCPServer(TCPServer, ForkingMixIn):\n",
    "    pass\n",
    "\n",
    "\n",
    "#编写一个多线程模式的UDP服务，定义如下：\n",
    "class MyUDPServer(UDPServer, ThreadingMixIn):\n",
    "    pass\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa59b060b12de523",
   "metadata": {},
   "source": [
    "## 定制类\n",
    "- 定制类，就是定义一个类，然后，在类中定义一个__str__()方法，当调用print()时，就会调用__str__()方法，返回一个字符串。类似java的toString()方法\n",
    "-\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ace41eaa7cd58bbc",
   "metadata": {},
   "source": [
    " #### __str__\n",
    "    类似java的toString()方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43eaafd1bbd4f7b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def __str__(self):\n",
    "        return \"Student object (name: %s)\" % self.name\n",
    "\n",
    "    __repr__ = __str__\n",
    "\n",
    "\n",
    "Student(\"xx\")\n",
    "print(Student(\"Michael\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "defb1c0b0a99a2b5",
   "metadata": {},
   "source": [
    "iter\n",
    "    类似java的iterable"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4790f9f1056bc244",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Fib(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        self.a, self.b = 0, 1  # 定义连个属性a,b\n",
    "\n",
    "    def __iter__(self):\n",
    "        return self  # iter\n",
    "\n",
    "    def __next__(self):\n",
    "        self.a, self.b = self.b, self.a + self.b  # 调用next\n",
    "        if self.a > 100000:  # 限制最大\n",
    "            raise StopIteration()\n",
    "        return self.a  # 返回下一个\n",
    "\n",
    "\n",
    "for n in Fib():\n",
    "    print(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "699dec9daedaaff2",
   "metadata": {},
   "source": [
    "#### getItem\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bbd2426f6fd79443",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Fib(object):\n",
    "\n",
    "    def __getitem__(self, n):\n",
    "        if isinstance(n, int):\n",
    "            a, b = 1, 1\n",
    "            for x in range(n):\n",
    "                a, b = b, a + b\n",
    "            return a\n",
    "        if isinstance(n, slice):\n",
    "            start = n.start\n",
    "            stop = n.stop\n",
    "            if start is None:\n",
    "                start = 0\n",
    "            a, b = 1, 1\n",
    "            L = []\n",
    "            for x in range(stop):\n",
    "                if x >= start:\n",
    "                    L.append(a)\n",
    "                a, b = b, a + b\n",
    "            return L\n",
    "\n",
    "\n",
    "f = Fib()\n",
    "print(f[0])\n",
    "print(f[5])\n",
    "print(f[100])\n",
    "print(f[0:5])\n",
    "print(f[:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8eba9c7236773e31",
   "metadata": {},
   "source": [
    "#### getStr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2199d8aa871cd7f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class Student2(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        self.name = \"Michael\"\n",
    "\n",
    "    def __getattr__(self, attr):\n",
    "        if attr == \"score\":\n",
    "            return 99\n",
    "        if attr == \"age\":\n",
    "            return lambda: 25\n",
    "        raise AttributeError(\"'Student' object has no attribute '%s'\" % attr)\n",
    "\n",
    "\n",
    "ss = Student2()\n",
    "print(ss.name)\n",
    "print(ss.score)\n",
    "print(ss.age())  #对应函数\n",
    "print(ss.age)\n",
    "try:\n",
    "    print(ss.grade)\n",
    "except AttributeError as e:\n",
    "    print(\"AttributeError:\", e)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fac16e51b8118a72",
   "metadata": {},
   "source": [
    "#### call"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "280070b195dbeae0",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def __call__(self):\n",
    "        print(\"My name is %s.\" % self.name)\n",
    "\n",
    "\n",
    "ss = Student(\"Michael\")\n",
    "ss()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87bea24fa8e9bd4c",
   "metadata": {},
   "source": [
    "#### 使用枚举类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67b87bdc420d12e7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from enum import Enum, unique\n",
    "\n",
    "\n",
    "@unique\n",
    "class Weekday(Enum):\n",
    "    Sun = 0\n",
    "    Mon = 1\n",
    "    Tue = 2\n",
    "    Wed = 3\n",
    "    Thu = 4\n",
    "    Fri = 5\n",
    "    Sat = 6\n",
    "\n",
    "\n",
    "day1 = Weekday.Mon\n",
    "\n",
    "print(\"day1 =\", day1)\n",
    "print(\"Weekday.Tue =\", Weekday.Tue)\n",
    "print(\"Weekday['Tue'] =\", Weekday[\"Tue\"])\n",
    "print(\"Weekday.Tue.value =\", Weekday.Tue.value)\n",
    "print(\"day1 == Weekday.Mon ?\", day1 == Weekday.Mon)\n",
    "print(\"day1 == Weekday.Tue ?\", day1 == Weekday.Tue)\n",
    "print(\"day1 == Weekday(1) ?\", day1 == Weekday(1))\n",
    "\n",
    "for name, member in Weekday.__members__.items():\n",
    "    print(name, \"=>\", member)\n",
    "\n",
    "Month = Enum(\"Month\", (\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"))\n",
    "\n",
    "for name, member in Month.__members__.items():\n",
    "    print(name, \"=>\", member, \",\", member.value)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ee28f93c69c2bee",
   "metadata": {},
   "source": [
    "#  数据库\n",
    "1. 连接数据库\n",
    "2. sqllite与mysql连接示例\n",
    "3. SQLAIchemy的使用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "555f715b1760767a",
   "metadata": {},
   "source": [
    "# Web开发\n",
    "1. wsgi\n",
    "2. flask\n",
    "3. flask模板"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "199c5cdf",
   "metadata": {},
   "source": [
    "# 多进程与多线程\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be2c2b7a",
   "metadata": {},
   "source": [
    "## 多进程\n",
    "子进程永远返回0，而父进程返回子进程的ID。这样做的理由是，一个父进程可以fork出很多子进程，所以，父进程要记下每个子进程的ID，而子进程只需要调用getppid()就可以拿到父进程的ID。\n",
    "\n",
    "Python的os模块封装了常见的系统调用，其中就包括fork，可以在Python程序中轻松创建子进程："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "52e02263",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Process (23684) start...\n",
      "I (23684) just created a child process (23732).\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "print('Process (%s) start...' % os.getpid())\n",
    "# Only works on Unix/Linux/macOS:\n",
    "pid = os.fork()\n",
    "if pid == 0:\n",
    "    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))\n",
    "else:\n",
    "    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "rag",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
